package com.wkg.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.wkg.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.wkg.lotterysystem.common.exception.ServiceException;
import com.wkg.lotterysystem.common.utils.JWTUtil;
import com.wkg.lotterysystem.common.utils.RegexUtil;
import com.wkg.lotterysystem.controller.param.UserLoginParam;
import com.wkg.lotterysystem.controller.param.UserPasswordLoginParam;
import com.wkg.lotterysystem.controller.param.UserRegisterParam;
import com.wkg.lotterysystem.controller.param.UserShortMessageLoginParam;
import com.wkg.lotterysystem.dao.dataobject.Encrypt;
import com.wkg.lotterysystem.dao.dataobject.UserDO;
import com.wkg.lotterysystem.service.dto.UserLoginDTO;
import com.wkg.lotterysystem.dao.mapper.UserMapper;
import com.wkg.lotterysystem.service.dto.UserDTO;
import com.wkg.lotterysystem.service.dto.UserRegisterDTO;
import com.wkg.lotterysystem.service.UserService;
import com.wkg.lotterysystem.service.VerificationCodeService;
import com.wkg.lotterysystem.service.enums.UserIdentityEnum;
import jakarta.validation.constraints.NotBlank;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 * 提供用户注册等核心业务逻辑的实现
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper; // 用户数据访问接口

    @Autowired
    private VerificationCodeService verificationCodeService;

    /**
     * 用户注册方法
     *
     * @param param 用户注册参数对象
     * @return 用户注册结果DTO
     * @throws ServiceException 当注册信息不合法时抛出业务异常
     */
    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        // 1. 校验注册信息合法性
        checkRegisterInfo(param);

        // 2. 构建数据库实体对象
        UserDO userDO = new UserDO();
        userDO.setUserName(param.getName());          // 设置用户名
        userDO.setIdentity(param.getIdentity());       // 设置用户身份
        userDO.setEmail(param.getMail());             // 设置邮箱
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber())); // 加密手机号

        // 如果有密码，则进行SHA256加密
        if (StringUtils.hasText(param.getPassword())) {
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }

        // 3. 保存用户数据到数据库
        userMapper.insert(userDO);

        // 4. 构建返回结果
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId()); // 设置返回的用户ID
        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO;

        //类型检查与类型转换. java14及以上版本可以一行代码完成两个操作
        if (param instanceof UserPasswordLoginParam loginParam) {
            userLoginDTO = loginByUserPassword(loginParam);
        } else if (param instanceof UserShortMessageLoginParam loginParam) {
            userLoginDTO = loginByShortMessage(loginParam);
        } else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXITS);
        }
        return userLoginDTO;
    }

    /**
     * 获取人员列表
     *
     * @param identity :如果为空，查询全部人员列表
     * @return
     */
    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        String identityString = null == identity ? null : identity.name();
        //查表
        List<UserDO> userDoList = userMapper.selectUserListByIdentity(identityString);
        List<UserDTO> userDTOList = userDoList.stream()
                .map(userDO -> {
                    UserDTO userDTO = new UserDTO();
                    userDTO.setUserId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEmail(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    return userDTO;
                }).collect(Collectors.toList());
        return userDTOList;
    }

    /**
     * 密码登录
     *
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDO userDO = null;
        //判断手机登录还是邮箱登录
        if (RegexUtil.checkMail(loginParam.getLoginName())) {
            //邮箱登录
            //根据邮箱查询用户表
            userDO = userMapper.selectByMail(loginParam.getLoginName());

        } else if (RegexUtil.checkMobile(loginParam.getLoginName())) {
            //手机号登录
            //根据手机号查询用户表
            userDO = userMapper.selectByPhone(new Encrypt(loginParam.getLoginName()));

        } else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }

        //校验单登录
        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
                && !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {
            //强制身份登录，身份校验不通过
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        } else if (!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())) {
            //校验密码
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //塞入返回值(JWT)
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("identity", userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setIdentity(userDO.getIdentity());
        userLoginDTO.setToken(token);
        return userLoginDTO;
    }


    /**
     * 验证码登录
     *
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByShortMessage(UserShortMessageLoginParam loginParam) {
        if (!RegexUtil.checkMobile(loginParam.getLoginMobile())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //获取用户数据
        UserDO userDO = userMapper.selectByPhone(new Encrypt(loginParam.getLoginMobile()));
        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
                && !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //校验验证码
        String code = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());
        if (!loginParam.getVerificationCode().equals(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        //塞入返回值(JWT)
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("identity", userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setIdentity(userDO.getIdentity());
        userLoginDTO.setToken(token);
        return userLoginDTO;
    }


    /**
     * 校验用户注册信息
     *
     * @param param 用户注册参数
     * @throws ServiceException 当任何一项校验不通过时抛出异常
     */
    private void checkRegisterInfo(UserRegisterParam param) {
        // 参数空值检查
        if (null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_EMPTY);
        }

        // 邮箱格式校验
        if (!RegexUtil.checkMail(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }

        // 手机号格式校验
        if (!RegexUtil.checkMobile(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        // 身份信息合法性校验
        if (null == UserIdentityEnum.forName(param.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        // 管理员密码必填校验
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }

        // 密码强度校验（至少6位）
        if (StringUtils.hasText(param.getPassword()) && !RegexUtil.checkPassword(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        // 邮箱唯一性校验
        if (checkMailUsed(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }

        // 手机号唯一性校验
        if (checkPhoneNumberUsed(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    /**
     * 检查手机号是否已被使用
     *
     * @param phoneNumber 待检查的手机号
     * @return true-已被使用 false-未被使用
     * @throws ServiceException 当手机号为空时抛出异常
     */
    private boolean checkPhoneNumberUsed(@NotBlank(message = "手机号不能为空") String phoneNumber) {
        // 查询数据库中该手机号的使用计数
        int count = userMapper.countByPhone(new Encrypt(phoneNumber));
        return count > 0;
    }

    /**
     * 检查邮箱是否已被使用
     *
     * @param mail 待检查的邮箱
     * @return true-已被使用 false-未被使用
     * @throws ServiceException 当邮箱为空时抛出异常
     */
    private boolean checkMailUsed(@NotBlank(message = "邮箱不能为空") String mail) {
        // 查询数据库中该邮箱的使用计数
        int count = userMapper.countByMail(mail);
        return count > 0;
    }
}
